/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package exatrez.manager;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.wideplay.warp.persist.Transactional;
import exatrez.dao.PenggunaDAO;
import exatrez.dao.PersonalTaskDAO;
import exatrez.model.PersonalTask;
import exatrez.model.User;
import exatrez.stripes.util.EmailUtil;
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import java.io.File;
import java.io.StringWriter;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Mansur
 */
public class CronPTaskManager {
    
    @Inject
    protected com.google.inject.Provider<Session> sessionProvider;
    @Inject
    Provider<SessionFactory> sp;
    @Inject
    exatrez.stripes.Configuration conf;
    @Inject
    private PersonalTaskDAO personalTaskDAO;
    @Inject
    private EmailUtil emailUtil;
    @Inject
    private PenggunaDAO penggunaDAO;
    
    private static Logger LOG = LoggerFactory.getLogger(CronPTaskManager.class);
    
    
//    scheduling not acquire after 3 days
    public void notAcquireTask(){
        Calendar cal = Calendar.getInstance();
        LOG.debug("notAcquireTask :"+cal.getTime());
        cal.add(Calendar.DATE, -3); //3 days not open Personal Task
        List<PersonalTask> tasks = this.findNotAquire(cal);
        LOG.debug("<notAcquireTask> tasks.size :"+tasks.size());
        for (PersonalTask pt : tasks) {
            LOG.debug("Personal Task ID :"+pt.getPersonalTaskId());
            pt.setAcquiredSts("Y");
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, pt.getPriorityDayCount());
            pt.setDuedate(c.getTime());
            this.updatePersonalTask(pt,0);
            this.sendEmailPasses(pt);
        }
    }
    
    private void sendEmailPasses(PersonalTask ptask) {
        if(ptask != null){
            try {
                // freemarker stuff.
                Configuration cfg = new Configuration();
                DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
                FileTemplateLoader templateLoader 
                        = new FileTemplateLoader(new File(conf.getProperty("email.template.path")));
                cfg.setTemplateLoader(templateLoader);
                cfg.setObjectWrapper(new DefaultObjectWrapper());
                Template template = cfg.getTemplate("html-task.ftl");
                Map<String, Object> rootMap = new HashMap<String, Object>();
                rootMap.put("subject", ptask.getSubject());
                rootMap.put("duedate", formatter.format(ptask.getDuedate()));

                Writer out = new StringWriter();
                template.process(rootMap, out);
                StatelessSession ss = null;
                ss = sp.get().openStatelessSession();
                Query query = ss.createQuery("from User u where u.userId = :userid").setParameter("userid", ptask.getToUser());
                User user = (User) query.uniqueResult();
                String [] recipient = {user.getEmail()};
//                String [] ccRecipient = {conf.getProperty("email.coo")};
                emailUtil.send(recipient, null, "ALERT : Personal Task 3 days passes.", out.toString(), "text/html");
                // freemarker stuff ends.
            } catch (Exception ex) {
                LOG.error("error occured {}!! ", ex);
            }
        }else{
            LOG.error("PersonalTask Is Null");
        }
    }
    
    private List<PersonalTask> findNotAquire(Calendar cal){
        StatelessSession ss = null;
        try{
            ss = sp.get().openStatelessSession();
            return ss.createQuery("from PersonalTask p where p.statusRemarks = 'Open' and p.acquiredSts = 'N' and date(p.infoAudit.createDate) = :date").setParameter("date", cal.getTime()).list();
        }catch(Exception ex){
            LOG.error(null, ex);
        }finally{
            ss.close();
        }
        return Collections.EMPTY_LIST;
    }
    
//    @Transactional
    private String updatePersonalTask(PersonalTask task, Integer point){
        String result = "success";
        Session ss = null;
        Transaction tx = null;
        try{
//            personalTaskDAO.saveOrUpdate(task);
            ss = sp.get().openSession();
            tx = ss.beginTransaction();
            Criteria query = ss.createCriteria(PersonalTask.class).add(Restrictions.eq("personalTaskId", task.getPersonalTaskId()));
            PersonalTask ptask = (PersonalTask) query.uniqueResult();
            LOG.debug("<updatePersonalTask> ptask.id :"+ptask.getPersonalTaskId());
            ptask.setAcquiredSts(task.getAcquiredSts());
            ptask.setDuedate(task.getDuedate());
            if(point != 0){
                ptask.setDeducePoint(task.getDeducePoint() + point);
            }
            ss.update(ptask);
            tx.commit();
        }catch(HibernateException ex){
            result = "fail";
            LOG.error("Fail to update PersonalTask : ", ex.getMessage());
            tx.rollback();
        }finally{
            if (ss != null) {
                ss.close();
            }
        }
        return result;
    }
    
//    @Transactional
    private String updateScorePoint(String userID, Integer point){
        String result = "success";
        Session ss = null;
        Transaction tx = null;
//        User user = penggunaDAO.findById(userID);
        try{
//            LOG.debug("UserID :"+user.getUserId()+", current ScorePoint :"+user.getScorePoint());
//            user.setScorePoint(user.getScorePoint() - point);
//            penggunaDAO.saveOrUpdate(user);            
            ss = sp.get().openSession();
            tx = ss.beginTransaction();
            Criteria query = ss.createCriteria(User.class).add(Restrictions.eq("userId", userID));
            User user = (User) query.uniqueResult();
            LOG.debug("<updateScorePoint>UserID :"+user.getUserId()+", current ScorePoint :"+user.getScorePoint());
            user.setScorePoint(user.getScorePoint() - point);
            ss.update(user);
            tx.commit();
        }catch(HibernateException ex){
            result = "Fail";
            LOG.error("Fail to update User :", ex.getMessage());
            tx.rollback();
        }finally{
            if (ss != null) {
                ss.close();
            }
        }
        
        return result;
    }
    
    //for 3 days before due date
    public void notRespondTask(){
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 3); //3 days before due date not respond Personal Task
        List<PersonalTask> tasks = this.findNotRespond(cal);
        LOG.debug("<notRespondTask> tasks.size :"+tasks.size());
        for (PersonalTask pt : tasks) {
            LOG.debug("Personal Task ID :"+pt.getPersonalTaskId());
            this.sendEmailBefore(pt);
        }
    }
    
    private void sendEmailBefore(PersonalTask ptask) {
        if(ptask != null){
            try {
                // freemarker stuff.
                Configuration cfg = new Configuration();
                DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
                FileTemplateLoader templateLoader 
                        = new FileTemplateLoader(new File(conf.getProperty("email.template.path")));
                cfg.setTemplateLoader(templateLoader);
                cfg.setObjectWrapper(new DefaultObjectWrapper());
                Template template = cfg.getTemplate("html-task-before.ftl");
                Map<String, Object> rootMap = new HashMap<String, Object>();
                rootMap.put("subject", ptask.getSubject());
                rootMap.put("duedate", formatter.format(ptask.getDuedate()));

                Writer out = new StringWriter();
                template.process(rootMap, out);
                StatelessSession ss = null;
                ss = sp.get().openStatelessSession();
                Query query = ss.createQuery("from User u where u.userId = :userid").setParameter("userid", ptask.getToUser());
                User user = (User) query.uniqueResult();
                String [] recipient = {user.getEmail()};
//                String [] recipient = {penggunaDAO.findById(ptask.getToUser()).getEmail()};
//                String [] ccRecipient = {conf.getProperty("email.coo")};
                emailUtil.send(recipient, null, "ALERT : Personal Task 3 days before due date.", out.toString(), "text/html");
                // freemarker stuff ends.
            } catch (Exception ex) {
                LOG.error("error occured {}!! ", ex);
            }
        }else{
            LOG.error("PersonalTask Is Null");
        }
    }
    
    private List<PersonalTask> findNotRespond(Calendar cal){
        StatelessSession ss = null;
        try{
            ss = sp.get().openStatelessSession();
            return ss.createQuery("from PersonalTask p where p.statusRemarks = 'Open' and p.flag = 1 and date(p.duedate) = :date").setParameter("date", cal.getTime()).list();
        }catch(Exception ex){
            LOG.error(null, ex);
        }finally{
            ss.close();
        }
        return Collections.EMPTY_LIST;
    }
    
    // at day due date, deduced 2 point.
    public void taskDueDate(){
        int point = Integer.parseInt(conf.getProperty("personal.point.deduction"));
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1); //at due date (yesterday due date)
        List<PersonalTask> tasks = this.findDueDateTask(cal);
        LOG.debug("<taskDueDate> tasks.size :"+tasks.size());
        for (PersonalTask pt : tasks) {
            LOG.debug("Personal Task ID :"+pt.getPersonalTaskId());
            this.sendEmailDueDate(pt);
//            pt.setDeducePoint(pt.getDeducePoint() + point);
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, pt.getPriorityDayCount());
            pt.setDuedate(c.getTime());
            this.updatePersonalTask(pt, point);
            this.updateScorePoint(pt.getToUser(), point);            
        }
    }
    
    
    private List<PersonalTask> findDueDateTask(Calendar cal){
        StatelessSession ss = null;
        try{
            ss = sp.get().openStatelessSession();
            return ss.createQuery("from PersonalTask p where p.statusRemarks = 'Open' and p.flag = 1 and p.duedate is not null and date(p.duedate) = :date").setParameter("date", cal.getTime()).list();
        }catch(Exception ex){
            LOG.error(null, ex);
        }finally{
            ss.close();
        }
        return Collections.EMPTY_LIST;
    }
    
    private void sendEmailDueDate(PersonalTask ptask) {
        int point = Integer.parseInt(conf.getProperty("personal.point.deduction"));
        if(ptask != null){
            try {
                // freemarker stuff.
                Configuration cfg = new Configuration();
                DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
                FileTemplateLoader templateLoader 
                        = new FileTemplateLoader(new File(conf.getProperty("email.template.path")));
                cfg.setTemplateLoader(templateLoader);
                cfg.setObjectWrapper(new DefaultObjectWrapper());
                Template template = null;
                if((ptask.getDeducePoint()/point) == 0){                        // 1st time duedate
                    template = cfg.getTemplate("html-task-duedate.ftl");
                }else if((ptask.getDeducePoint()/point) == 1){                  // 2nd time duedate
                    template = cfg.getTemplate("html-task-duedate2.ftl");
                }else{                                                          // 3rd and so on duedate
                    template = cfg.getTemplate("html-task-duedate3.ftl");
                }
                
                Map<String, Object> rootMap = new HashMap<String, Object>();
                rootMap.put("subject", ptask.getSubject());
                rootMap.put("duedate", formatter.format(ptask.getDuedate()));
                rootMap.put("deducepoint", conf.getProperty("personal.point.deduction"));
                rootMap.put("priorityday", ptask.getPriorityDayCount());

                Writer out = new StringWriter();
                template.process(rootMap, out);
                StatelessSession ss = null;
                ss = sp.get().openStatelessSession();
                Query query = ss.createQuery("from User u where u.userId = :userid").setParameter("userid", ptask.getToUser());
                User user = (User) query.uniqueResult();
                String [] recipient = {user.getEmail()};
//                String [] recipient = {penggunaDAO.findById(ptask.getToUser()).getEmail()};
//                String [] ccRecipient = {conf.getProperty("email.coo")};
                String [] ccRecipient = conf.getProperty("email.ptask.coo").split(",");
//                String [] ccRecipient = {"ahmad.coo@iconoffshore.com.my","abumansurmaturidi@gmail.com"};
                emailUtil.send(recipient, ccRecipient, "WARNING : Personal Task due date.", out.toString(), "text/html");
                // freemarker stuff ends.
            } catch (Exception ex) {
                LOG.error("error occured {}!! ", ex);
            }
        }else{
            LOG.error("PersonalTask Is Null");
        }
    }
}
